/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */

#include "at32f421.h"
#include <rtthread.h>
#include "ringbuffer.h"
#include <stdbool.h>

#define USART2_DMA_BUFFER_SIZE 64
#define USART1_DMA_BUFFER_SIZE 64
#define USART_RINGBUFFER_SIZE 64

bool isThreadStarted = false;
bool AT_CMD_ON =0;

uint8_t usart2_dma_tx_buffer[USART2_DMA_BUFFER_SIZE];
uint8_t usart2_dma_rx_buffer[USART1_DMA_BUFFER_SIZE];
uint8_t usart1_dma_tx_buffer[USART2_DMA_BUFFER_SIZE];
uint8_t usart1_dma_rx_buffer[USART2_DMA_BUFFER_SIZE];

volatile uint8_t usart2_tx_dma_status = 0;
volatile uint8_t usart2_rx_dma_status = 0;
volatile uint8_t usart1_tx_dma_status = 0;
volatile uint8_t usart1_rx_dma_status = 0;

uint16_t usart2_rxlen = 0;
uint16_t usart1_rxlen = 0;
struct rt_ringbuffer usart2_rxrb;
struct rt_ringbuffer usart1_rxrb;
uint8_t u2_rx_ringbuffer[USART_RINGBUFFER_SIZE];
uint8_t u1_rx_ringbuffer[USART_RINGBUFFER_SIZE];

void usart_configuration(void)
{
    gpio_init_type gpio_init_struct;

    /* enable the usart2 and gpio clock */
    crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

    gpio_default_para_init(&gpio_init_struct);
    /* configure the usart2 tx/rx pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_3;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);

    /* config usart2 iomux */
    gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE2, GPIO_MUX_1);
    gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE3, GPIO_MUX_1);

    /* configure usart2 param */
    usart_init(USART2, 921600, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_transmitter_enable(USART2, TRUE);
    usart_receiver_enable(USART2, TRUE);
    usart_dma_transmitter_enable(USART2, TRUE);
    usart_dma_receiver_enable(USART2, TRUE);
    usart_enable(USART2, TRUE);
    nvic_irq_enable(USART2_IRQn, 0, 0);
    usart_interrupt_enable(USART2, USART_IDLE_INT, TRUE);

    /* configure the usart1 tx/rx pin */
    /* enable the usart1 and gpio clock */
    crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
    gpio_init_struct.gpio_pins = GPIO_PINS_6 | GPIO_PINS_7;
    gpio_init(GPIOB, &gpio_init_struct);

    /* config usart1 iomux */
    gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE6, GPIO_MUX_0);
    gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE7, GPIO_MUX_0);

    /* configure usart1 param */
    usart_init(USART1, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_transmitter_enable(USART1, TRUE);
    usart_receiver_enable(USART1, TRUE);
    usart_dma_transmitter_enable(USART1, TRUE);
    usart_dma_receiver_enable(USART1, TRUE);
    usart_enable(USART1, TRUE);
    nvic_irq_enable(USART1_IRQn, 0, 0);
    usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE);
}
void uart2_cosole_init(void)
{
    gpio_init_type gpio_init_struct;
    /* enable the usart2 and gpio clock */
    crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

    gpio_default_para_init(&gpio_init_struct);
    /* configure the usart2 tx/rx pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_3;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);

    /* config usart2 iomux */
    gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE2, GPIO_MUX_1);
    gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE3, GPIO_MUX_1);

    /* configure usart2 param */
    usart_init(USART2, 921600, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_transmitter_enable(USART2, TRUE);
    usart_receiver_enable(USART2, TRUE);
    usart_enable(USART2, TRUE);
}
/**
 * @brief  config dma for usart2 and usart1
 * @param  none
 * @retval none
 */
void dma_configuration(void)
{
    dma_init_type dma_init_struct;

    /* enable dma1 clock */
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);

    /* dma1 channel4 for usart2 tx configuration */
    dma_reset(DMA1_CHANNEL4);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = 0;
    dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_base_addr = (uint32_t)usart2_dma_tx_buffer;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&USART2->dt;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA1_CHANNEL4, &dma_init_struct);

    /* enable transfer full data interrupt */
    dma_interrupt_enable(DMA1_CHANNEL4, DMA_FDT_INT, TRUE);

    /* dma1 channel4 interrupt nvic init */
    nvic_irq_enable(DMA1_Channel5_4_IRQn, 0, 0);

    /* dma1 channel5 for usart2 rx configuration */
    dma_reset(DMA1_CHANNEL5);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = USART2_DMA_BUFFER_SIZE;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t)usart2_dma_rx_buffer;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&USART2->dt;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = TRUE;
    dma_init(DMA1_CHANNEL5, &dma_init_struct);

    /* enable transfer full data interrupt */
    // dma_interrupt_enable(DMA1_CHANNEL5, DMA_FDT_INT, TRUE);

    /* dma1 channel5 interrupt nvic init */
    nvic_irq_enable(DMA1_Channel5_4_IRQn, 0, 0);

    dma_channel_enable(DMA1_CHANNEL5, TRUE); /* usart2 rx begin dma receiving */
                                             // dma_channel_enable(DMA1_CHANNEL4, TRUE); /* usart2 tx begin dma transmitting */
#if 1
    /* dma1 channel2 for usart1 tx configuration */
    dma_reset(DMA1_CHANNEL2);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = 0;
    dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_base_addr = (uint32_t)usart1_dma_tx_buffer;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA1_CHANNEL2, &dma_init_struct);

    /* enable transfer full data interrupt */
    dma_interrupt_enable(DMA1_CHANNEL2, DMA_FDT_INT, TRUE);

    /* dma1 channel2 interrupt nvic init */
    nvic_irq_enable(DMA1_Channel3_2_IRQn, 0, 0);

    /* dma1 channel3 for usart1 rx configuration */
    dma_reset(DMA1_CHANNEL3);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = USART2_DMA_BUFFER_SIZE;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t)usart1_dma_rx_buffer;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA1_CHANNEL3, &dma_init_struct);

    /* enable transfer full data interrupt */
    dma_interrupt_enable(DMA1_CHANNEL3, DMA_FDT_INT, TRUE);

    /* dma1 channel3 interrupt nvic init */
    nvic_irq_enable(DMA1_Channel3_2_IRQn, 0, 0);
    // dma_channel_enable(DMA1_CHANNEL2, TRUE); /* usart1 tx begin dma transmitting */
    dma_channel_enable(DMA1_CHANNEL3, TRUE); /* usart1 rx begin dma receiving */
#endif
}

uint16_t uart2_put(uint8_t *buf, uint16_t len)
{
    if (!isThreadStarted)
    {
        for (uint8_t i = 0; i < len; i++)
        {
            usart_data_transmit(USART2, buf[i]);
            while (usart_flag_get(USART2, USART_TDC_FLAG) == RESET)
                ;
        }
        return len;
    }

    while (usart2_tx_dma_status == 1)
        ;

    usart2_tx_dma_status = 1;
    rt_memcpy(usart2_dma_tx_buffer, buf, (len > USART2_DMA_BUFFER_SIZE ? USART2_DMA_BUFFER_SIZE : len));
    dma_data_number_set(DMA1_CHANNEL4, len);
    dma_channel_enable(DMA1_CHANNEL4, TRUE); /* usart2 tx begin dma transmitting */

    // DMA1_CHANNEL4->maddr = (uint32_t)buf;
    // DMA1_CHANNEL4->dtcnt = len;
    // DMA1_CHANNEL4->ctrl_bit.chen = TRUE;
    return len;
}
uint16_t uart1_put(uint8_t *buf, uint16_t len)
{
    while (usart1_tx_dma_status == 1)
        ;
    rt_memcpy(usart1_dma_tx_buffer, buf, (len > USART1_DMA_BUFFER_SIZE ? USART1_DMA_BUFFER_SIZE : len));
    usart1_tx_dma_status = 1;
    dma_data_number_set(DMA1_CHANNEL2, len);
    dma_channel_enable(DMA1_CHANNEL2, TRUE); /* usart2 tx begin dma transmitting */
    return len;
}

uint16_t uart2_get(uint8_t *buf, uint16_t len)
{
    return rt_ringbuffer_get(&usart2_rxrb, buf, len);
}
uint16_t uart2_getAll(uint8_t *buf)
{
    // 获取串口2接收缓冲区中的数据长度
    uint16_t len = rt_ringbuffer_data_len(&usart2_rxrb);
    // 从串口2接收缓冲区中获取数据
    return rt_ringbuffer_get(&usart2_rxrb, buf, len);
}
// 从usart1_rxrb环形缓冲区中获取数据，存入buf中，返回获取到的数据长度
uint16_t uart1_get(uint8_t *buf, uint16_t len)
{
    return rt_ringbuffer_get(&usart1_rxrb, buf, len);
}
int16_t uart1_getChar(void)
{
    uint8_t c;
    if(rt_ringbuffer_getchar(&usart1_rxrb, &c) == 1) {
        return c;
    }
    return -1;
}
uint8_t *uart1_rxbuffer(void)
{
    return usart1_dma_rx_buffer;
}
uint16_t uart1_rx_length(void)
{
    return usart1_rxlen;
}
// 获取串口1接收缓冲区中的所有数据
uint16_t uart1_getAll(uint8_t *buf)
{
    // 获取串口1接收缓冲区中的数据长度
    uint16_t len = rt_ringbuffer_data_len(&usart1_rxrb);
    // 从串口1接收缓冲区中获取数据
    return rt_ringbuffer_get(&usart1_rxrb, buf, len);
}
uint8_t *uart1_rxBuff(void)
{
    return usart1_dma_rx_buffer;
}
uint16_t uart1_rxLen(void)
{
    return usart1_rxlen;
}
void USART2_IRQHandler(void)
{
    rt_interrupt_enter();
    if (usart_interrupt_flag_get(USART2, USART_IDLEF_FLAG) != RESET)
    {
        usart_flag_clear(USART2, USART_IDLEF_FLAG);
        dma_channel_enable(DMA1_CHANNEL5, FALSE);
        uint16_t rb = USART2_DMA_BUFFER_SIZE - dma_data_number_get(DMA1_CHANNEL5);
        rt_ringbuffer_put(&usart2_rxrb, usart2_dma_rx_buffer, rb);
        dma_data_number_set(DMA1_CHANNEL5, USART2_DMA_BUFFER_SIZE);
        dma_channel_enable(DMA1_CHANNEL5, TRUE);

        if(AT_CMD_ON)
            uart1_put(usart2_dma_rx_buffer, rb);
    }
    rt_interrupt_leave();
}
void USART1_IRQHandler(void)
{
    rt_interrupt_enter();
    if (usart_interrupt_flag_get(USART1, USART_IDLEF_FLAG) != RESET)
    {
        usart_flag_clear(USART1, USART_IDLEF_FLAG);
        dma_channel_enable(DMA1_CHANNEL3, FALSE);
        usart1_rxlen = USART1_DMA_BUFFER_SIZE - dma_data_number_get(DMA1_CHANNEL3);
        rt_ringbuffer_put(&usart1_rxrb, usart1_dma_rx_buffer, usart1_rxlen);
        dma_data_number_set(DMA1_CHANNEL3, USART1_DMA_BUFFER_SIZE);
        dma_channel_enable(DMA1_CHANNEL3, TRUE);

        if(AT_CMD_ON)
            uart2_put(usart1_dma_rx_buffer, usart1_rxlen);
    }
    rt_interrupt_leave();
}
/**
 * @brief  this function handles dma1 channel2/3 handler.
 * @param  none
 * @retval none
 */
void DMA1_Channel3_2_IRQHandler(void)
{
    rt_interrupt_enter();
    if (dma_interrupt_flag_get(DMA1_FDT2_FLAG))
    {
        usart1_tx_dma_status = 0;
        dma_flag_clear(DMA1_FDT2_FLAG);
        dma_channel_enable(DMA1_CHANNEL2, FALSE);
    }
    else if (dma_interrupt_flag_get(DMA1_FDT3_FLAG))
    {
        usart1_rx_dma_status = 1;
        dma_flag_clear(DMA1_FDT3_FLAG);
        dma_channel_enable(DMA1_CHANNEL3, FALSE);
    }
    rt_interrupt_leave();
}

/**
 * @brief  this function handles dma1 channel4/5 handler.
 * @param  none
 * @retval none
 */
void DMA1_Channel5_4_IRQHandler(void)
{
    // rt_kprintf("DMA1_Channel5_4_IRQHandler\n");
    rt_interrupt_enter();
    if (dma_interrupt_flag_get(DMA1_FDT4_FLAG))
    {
        usart2_tx_dma_status = 0;
        dma_flag_clear(DMA1_FDT4_FLAG);
        dma_channel_enable(DMA1_CHANNEL4, FALSE);
    }
    if (dma_interrupt_flag_get(DMA1_FDT5_FLAG))
    {
        usart2_rx_dma_status = 1;
        dma_flag_clear(DMA1_FDT5_FLAG);
    }
    rt_interrupt_leave();
}

void rt_hw_console_output(const char *str)
{
    uint16_t len = rt_strlen(str);
    uart2_put((uint8_t *)str, len);
}

#ifdef RT_USING_FINSH
char rt_hw_console_getchar(void)
{
    uint8_t ch = -1;
    rt_ringbuffer_getchar(&usart2_rxrb, &ch);
    return ch;
}
#endif
int uart_init(void)
{
    usart_configuration();
    dma_configuration();

    rt_ringbuffer_init(&usart2_rxrb, u2_rx_ringbuffer, USART_RINGBUFFER_SIZE);
    rt_ringbuffer_init(&usart1_rxrb, u1_rx_ringbuffer, USART_RINGBUFFER_SIZE);

    return 0;
}
void AT(int argc, char **argv)
{
    if(rt_strncmp(argv[1], "ON", 2) == 0) {
        AT_CMD_ON = 1;
    }
    else if(rt_strncmp(argv[1], "OFF", 3) == 0) {
        AT_CMD_ON = 0;
    }
    else
    {
        rt_kprintf("usage: AT ON/OFF\n");
        rt_kprintf("   ON: enable bluetooth AT cmd\n");
        rt_kprintf("  OFF: disable bluetooth AT cmd\n");
    }
}
MSH_CMD_EXPORT(AT, bluetooth AT cmd on/off);
// INIT_BOARD_EXPORT(uart_init);
